import * as THREE from 'three'
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js'
import * as CANNON from 'cannon-es'

const world = new CANNON.World()
world.gravity.set(0, -0.98, 0) // 设置重力
world.allowSleep = true

const scene = new THREE.Scene()

const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight)
camera.position.set(0, 3, 5)
scene.add(camera)

const renderer = new THREE.WebGLRenderer({ antialias: true })
renderer.setSize(window.innerWidth, window.innerHeight)
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2))
renderer.shadowMap.enabled = true
renderer.outputColorSpace = THREE.SRGBColorSpace

const controls = new OrbitControls(camera, renderer.domElement)
controls.enableDamping = true

document.body.appendChild(renderer.domElement)

const axHelp = new THREE.AxesHelper(5)
scene.add(axHelp)

const light = new THREE.AmbientLight('#fff', 3)
scene.add(light)

const geometry = new THREE.BoxGeometry(1, 1, 1)
const geoMaterial = new THREE.MeshBasicMaterial({ color: 'red' })

const shape = new CANNON.Box(new CANNON.Vec3(0.5, 0.5, 0.5))


const meshes: THREE.Mesh[] = []
const bodyMeshes: CANNON.Body[] = []

let preBody:CANNON.Body = null!

for(let i = -3; i < 3; i++) {
  const mesh = new THREE.Mesh(geometry, geoMaterial)
  scene.add(mesh)
  meshes.push(mesh)
  const body = new CANNON.Body({
    shape, position: new CANNON.Vec3(i + 0.2 * i, 4, 0), mass: 1,
  })
  world.addBody(body)
  bodyMeshes.push(body)
  if(preBody) {
    const lock = new CANNON.LockConstraint(body, preBody)
    world.addConstraint(lock)
  }
  preBody = body
}

const plane = new THREE.Mesh(
  new THREE.PlaneGeometry(10, 10),
  new THREE.MeshBasicMaterial({ color: 'grey' })
)
plane.rotation.x = -Math.PI / 2
scene.add(plane)

const planeMaterial = new CANNON.Material('ground')
planeMaterial.friction = 0
planeMaterial.restitution = 0

const planeBody = new CANNON.Body({
  type: CANNON.Body.STATIC,
  material: planeMaterial,
}).addShape(new CANNON.Plane())
planeBody.quaternion.setFromAxisAngle(new CANNON.Vec3(1, 0, 0), -Math.PI / 2)
world.addBody(planeBody)


const clock = new THREE.Clock()
let preTime = 0

const handleRender = () => {
  const nowTime = clock.getElapsedTime()
  const deltaTime = nowTime - preTime
  preTime = nowTime

  world.step(1 / 60, deltaTime, 3) // 补帧操作
  for(let i = 0; i < meshes.length; i++) {
    meshes[i].position.copy(bodyMeshes[i].position as any)
    meshes[i].quaternion.copy(bodyMeshes[i].quaternion as any)
  }

  controls.update()
  renderer.render(scene, camera)
  window.requestAnimationFrame(handleRender)
}

const handleSize = () => {
  camera.aspect = window.innerWidth / window.innerHeight
  camera.updateProjectionMatrix()

  renderer.setSize(window.innerWidth, window.innerHeight)
  renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2))
}

window.addEventListener('resize', handleSize)

handleRender()
